home *** CD-ROM | disk | FTP | other *** search
- // BrowserPane.m
- //
- // Free software created 1 Feb 1992
- // by Paul Burchard <burchard@math.utah.edu>.
-
- #import "BrowserPane.h"
- #import <objc/Storage.h>
- #import <appkit/appkit.h>
- #import <string.h>
- #import <sys/types.h>
- #import <sys/stat.h>
- #import <sys/file.h>
-
- @implementation BrowserPane
-
-
- // Init, freeing, archiving.
-
- - initFrame:(const NXRect *)frameRect
- {
- return [self initFrame:frameRect cellClass:[TextFieldCell class]];
- }
-
- - initFrame:(const NXRect *)frameRect cellClass:factoryId
- {
- id matrix;
- NXRect subframe;
- NXSize cellsize;
-
- [super initFrame:frameRect];
- [self setBorderType:NX_BEZEL];
- [self setBackgroundGray:NX_LTGRAY];
- [self setVertScrollerRequired:YES];
- [self setAutoresizeSubviews:YES];
- action = @selector(takeStringValueFrom:);
- doubleAction = @selector(takeStringValueFrom:);
- stringValue = [[Storage alloc] initCount:0 elementSize:sizeof(char) description:"c"];
- stringList = [[List alloc] initCount:0];
- separator = '\t';
-
- // Create Matrix of full-width Cells of class factoryId,
- // and place in our scrollView as its docView.
- [contentView getFrame:&subframe];
- matrix = [[Matrix alloc] initFrame:&subframe mode:NX_LISTMODE cellClass:factoryId numRows:0 numCols:1];
- if(!matrix) return nil;
- cellsize.width = cellsize.height = 0.0;
- [matrix setIntercell:&cellsize];
- [matrix getCellSize:&cellsize];
- cellsize.width = NX_WIDTH(&subframe);
- [matrix setCellSize:&cellsize];
- [matrix setAutosizeCells:YES];
- [matrix setAutoscroll:YES];
- [[matrix setAction:@selector(sendAction)] setTarget:self];
- [matrix setDoubleAction:@selector(sendDoubleAction)];
- [self setDocView:matrix];
- [matrix sizeToCells];
- [self setAutodisplay:YES];
- [self setNeedsDisplay:YES];
-
- return self;
- }
-
- - resizeSubviews:(const NXSize *)oldSize
- {
- NXRect contentFrame, docFrame;
-
- [super resizeSubviews:oldSize];
-
- // Keep matrix at full width of contentView when size changes.
- [contentView getFrame:&contentFrame];
- [contentView convertRect:&contentFrame toView:contentView];//paranoia
- [[self docView] getFrame:&docFrame];
- [[self docView] sizeTo:NX_WIDTH(&contentFrame) :NX_HEIGHT(&docFrame)];
- return self;
- }
-
- - read:(NXTypedStream *)stream
- {
- [super read:stream];
- stringValue = NXReadObject(stream);
- stringList = NXReadObject(stream);
- delegate = NXReadObject(stream);
- target = NXReadObject(stream);
- // Assumes BOOL is size of char.
- NXReadTypes(stream, "::ccccc", &action, &doubleAction,
- &isAlphabetized, &isAbbreviated, &isEditable, &isDisabledOnEntry,
- &separator);
- return self;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteObject(stream, stringValue);
- NXWriteObject(stream, stringList);
- NXWriteObjectReference(stream, delegate);
- NXWriteObjectReference(stream, target);
- // Assumes BOOL is size of char.
- NXWriteTypes(stream, "::ccccc", &action, &doubleAction,
- &isAlphabetized, &isAbbreviated, &isEditable, &isDisabledOnEntry,
- &separator);
- return self;
- }
-
- - free
- {
- [stringValue free];
- [[stringList freeObjects] free];
- return [super free];
- }
-
-
- // Adding and removing entries.
-
- // Internal use only.
- - (int)indexAddEntryStorage:stringStorage
- {
- int row, nrows, ncols, len;
- id matrix;
- char *newName, *abbrevName = 0;
- const char *name;
-
- // Don't enter again if already in here.
- if(!stringStorage) return (-1);
- if(!(newName = [stringStorage elementAt:0])) return (-1);
- if((row=[self indexOfEntry:newName]) >= 0)
- { [stringStorage free]; return row; }
-
- // Get abbreviation if necessary.
- if(isAbbreviated)
- {
- len = strlen(newName);
- [stringStorage setNumSlots:2*(len+1)];
- abbrevName = (char *)[stringStorage elementAt:(len+1)];
- newName = (char *)[stringStorage elementAt:0];
- if(!abbrevName || !newName) return (-1);
- *abbrevName = 0;
- [self abbreviate:newName to:abbrevName];
- }
-
- // Find slot for new entry (sort by abbreviated forms).
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- if(isAlphabetized) for(row=0; row<nrows; row++)
- {
- name = [[matrix cellAt:row :0] stringValue];
- if(isAbbreviated && [self isFirst:abbrevName second:name]) break;
- if(!isAbbreviated && [self isFirst:newName second:name]) break;
- }
- else row = nrows;
-
- // Insert new entry into matrix and string list, disabling if req'd.
- [matrix insertRowAt:row];
- [matrix sizeToCells];
- [[matrix cellAt:row :0]
- setStringValue:(isAbbreviated ? abbrevName : newName)];
- [stringList insertObject:stringStorage at:row];
- if(isDisabledOnEntry) [self setEntryEnabled:NO at:row];
- return row;
- }
-
- - (int)indexAddEntry:(const char *)aString
- {
- int row, len;
- id stringStorage;
-
- if(!aString) return (-1);
- len = strlen(aString);
- stringStorage = [[Storage alloc] initCount:(len+1) elementSize:sizeof(char) description:"c"];
- [stringStorage setNumSlots:(len+1)];
- strcpy((char *)[stringStorage elementAt:0], aString);
- row = [self indexAddEntryStorage:stringStorage];
- if(row < 0) { [stringStorage free]; return (-1); }
- return row;
- }
-
- - addEntry:(const char *)aString
- {
- if([self indexAddEntry:aString] < 0) return nil;
- else return self;
- }
-
- - (const char *)entryAt:(int)row
- {
- return (const char *)[[stringList objectAt:row] elementAt:0];
- }
-
- - cellAt:(int)row
- {
- return [[self docView] cellAt:row :0];
- }
-
- - (int)indexOfEntry:(const char *)aString
- {
- int row, nrows, ncols;
- id matrix;
-
- if(!aString) return (-1);
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- for(row=0; row<nrows; row++)
- if(strcmp([self entryAt:row], aString) == 0) break;
- if(row >= nrows) return (-1);
- return row;
- }
-
- - (unsigned)count
- {
- int nrows = (-1), ncols = (-1);
-
- [[self docView] getNumRows:&nrows numCols:&ncols];
- if(nrows < 0) return 0;
- else return nrows;
- }
-
- - removeEntryAt:(int)row
- {
- int nrows, ncols;
- id matrix;
-
- // Removing a selected entry clears the selection.
- matrix = [self docView];
- if([self isEntrySelectedAt:row]) [self clearSelection];
-
- // Remove entry and resize Matrix.
- [matrix getNumRows:&nrows numCols:&ncols];
- if(row<0 || row>=nrows) return nil;
- [matrix removeRowAt:row andFree:YES];
- [matrix sizeToCells];
- [[stringList removeObjectAt:row] free];
- return self;
- }
-
- - removeSelection
- {
- int row, nrows, ncols;
- id matrix;
-
- // Remove selected entries (starting from last) and resize Matrix.
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- for(row=nrows-1; row>=0; row--) if([self isEntrySelectedAt:row])
- {
- [matrix removeRowAt:row andFree:YES];
- [[stringList removeObjectAt:row] free];
- }
- [matrix sizeToCells];
- [self clearSelection];
- return self;
- }
-
- - clear
- {
- int row, nrows, ncols;
- id matrix;
-
- [self clearSelection];
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- for(row=nrows-1; row>=0; row--)
- {
- [matrix removeRowAt:row andFree:YES];
- [[stringList removeObjectAt:row] free];
- }
- [matrix sizeToCells];
- return self;
- }
-
- - addFiles:(const char *)dir suffix:(const char *)sfx;
- {
- char command[2048], *fgets(), *name;
- FILE *pipe;
- struct stat statbuf;
-
- sprintf(command, "/bin/ls -1d 2>/dev/null %s/*", dir);
- if(sfx != NULL) { strcat(command, "."); strcat(command, sfx); }
- pipe = popen(command, "r");
- while(fgets(command, 2048, pipe) != NULL)
- {
- command[strlen (command) - 1] = '\0';
- stat(command, &statbuf);
- if((name = strrchr(command, '/')) != NULL) name++;
- else name = command;
- if(!(statbuf.st_mode & S_IFDIR)) [self addEntry:name];
- }
- pclose(pipe);
- return self;
- }
-
-
- // Adding and selecting entries via stringValue.
-
- - (const char *)grabStringFrom:sender
- {
- if([sender respondsTo:@selector(stringValue)])
- return [sender stringValue];
- else if([sender respondsTo:@selector(stringValueAt:)])
- return [sender stringValueAt:0];
- else return (const char *)0;
- }
-
- - (const char *)stringValue
- {
- if([stringValue count] <= 0) return 0;
- return (const char *)[stringValue elementAt:0];
- }
-
- - setStringValue:(const char *)aString
- {
- return [self setStringValue:aString append:NO];
- }
-
- - setStringValue:(const char *)aString append:(BOOL)yn
- {
- int row, len;
- const char *nextString;
- char *endOfEntry;
- id nextEntry;
-
- // Clear selection first if not appending to stringValue.
- if(!yn || !aString) [self clearSelection];
- if(!aString) return self;
-
- // Add TAB-separated items to selection.
- // If not already in matrix and list, add them.
- for(nextString=aString; nextString;
- nextString=strchr(nextString, separator))
- {
- // Create Storage string to hold unabbrev next entry.
- if(*nextString == separator) nextString++;
- len = strlen(nextString);
- nextEntry = [[Storage alloc] initCount:(len+1) elementSize:sizeof(char) description:"c"];
- [nextEntry setNumSlots:(len+1)];
- strcpy((char *)[nextEntry elementAt:0], nextString);
- endOfEntry = strchr((char *)[nextEntry elementAt:0], separator);
- if(endOfEntry) *endOfEntry = 0;
-
- // Add to matrix and list if necessary, disabled if req'd.
- row = [self indexAddEntryStorage:nextEntry];
- if(row < 0) { [nextEntry free]; return nil; }
- if(isDisabledOnEntry) [self setEntryEnabled:NO at:row];
-
- // Add entry to selection.
- if(!isDisabledOnEntry) [self selectEntryAt:row append:YES];
- }
- [self update];
- return self;
- }
-
- - takeStringValueFrom:sender
- {
- id oldTarget = nil;
- id rtn;
-
- // If sender is target, don't send action (to avoid circularity).
- if(sender == target) { oldTarget = target; [self setTarget:nil]; }
- rtn = [self setStringValue:[self grabStringFrom:sender] append:NO];
- if(oldTarget) [self setTarget:oldTarget];
-
- // Notify delegate of user-induced change in list.
- // (Actually, due to non-duplication no change may have taken place.)
- if([delegate respondsTo:@selector(textDidChange:)])
- [delegate textDidChange:self];
- return rtn;
- }
-
- - appendStringValueFrom:sender
- {
- id oldTarget = nil;
- id rtn;
-
- // If sender is target, don't send action (to avoid circularity).
- if(sender == target) { oldTarget = target; [self setTarget:nil]; }
- rtn = [self setStringValue:[self grabStringFrom:sender] append:YES];
- if(oldTarget) [self setTarget:oldTarget];
-
- // Notify delegate of user-induced change in list.
- // (Actually, due to non-duplication no change may have taken place.)
- if([delegate respondsTo:@selector(textDidChange:)])
- [delegate textDidChange:self];
- return rtn;
- }
-
- - (char)separator
- {
- return separator;
- }
-
- - setSeparator:(char)c
- {
- if(!c) return nil;
- separator = c;
- return self;
- }
-
-
- // Selecting.
-
- - selectEntryAt:(int)row append:(BOOL)yn
- {
- int nrows, ncols, oldlen;
- const char *entryString;
- id matrix;
-
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- if(row<0 || row>=nrows) return nil;
- if(![self isEntryEnabledAt:row]) return nil;
- entryString = (char *)[[stringList objectAt:row] elementAt:0];
-
- if(yn)
- {
- // Append to selection.
- // Selection indicated by cell state and highlighting.
- [matrix lockFocus];
- [matrix highlightCellAt:row :0 lit:YES];
- [matrix setState:1 at:row :0];
- [matrix unlockFocus];
- if([stringValue count] <= 0) oldlen = 0;
- else oldlen = strlen((char *)[stringValue elementAt:0]);
- [stringValue setNumSlots:(oldlen + 1 + strlen(entryString) + 1)];
- sprintf((char *)[stringValue elementAt:0] + oldlen,
- (oldlen>0 ? "\t%s" : "%s"), entryString);
- }
- else
- {
- // Create new selection.
- // Selection indicated by cell state and highlighting.
- [self clearSelection];
- [matrix lockFocus];
- [matrix highlightCellAt:row :0 lit:YES];
- [matrix setState:1 at:row :0];
- [matrix unlockFocus];
- [stringValue setNumSlots:(strlen(entryString)+1)];
- strcpy((char *)[stringValue elementAt:0], entryString);
- }
-
- // Notify target of new selection.
- if(action) [target perform:action with:self];
- return self;
- }
-
- - (BOOL)isEntrySelectedAt:(int)row
- {
- int nrows, ncols;
- id matrix;
-
- // Selection indicated by cell state and highlighting.
- // Make sure state is consistent with highlighting and enabling.
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- if(row<0 || row>=nrows) return NO;
- if(![self isEntryEnabledAt:row] || ![[matrix cellAt:row :0] isHighlighted])
- {
- [matrix setState:0 at:row :0];
- return NO;
- }
- [matrix setState:1 at:row :0];
- return YES;
- }
-
- - clearSelection
- {
- int row, nrows, ncols;
- id matrix;
-
- matrix = [self docView];
- [matrix selectCellAt:(-1) :(-1)];
- [matrix getNumRows:&nrows numCols:&ncols];
- [matrix lockFocus];
- for(row=0; row<nrows; row++)
- {
- // Selection indicated by cell state and highlighting.
- [matrix highlightCellAt:row :0 lit:NO];
- [matrix setState:0 at:row :0];
- }
- [matrix unlockFocus];
- [stringValue setNumSlots:0];
- if(action) [target perform:action with:self];
- return self;
- }
-
-
- // Target and action.
-
- // For internal use only.
- - (BOOL)appendSelStringFrom:sender
- {
- int row, oldlen;
- const char *nextString;
-
- // Find (enabled) cell and its unabbreviated stringValue.
- if((row=[[[self docView] cellList] indexOf:sender]) == NX_NOT_IN_LIST)
- return NO;
- if(![self isEntryEnabledAt:row]) return YES; // continue looping thru cells
- nextString = (char *)[[stringList objectAt:row] elementAt:0];
-
- // Selection indicated by cell state and highlighting.
- // Make sure state is consistent with highlighting.
- if(![sender isHighlighted])
- {
- [sender setState:0];
- return YES; // continue looping thru cells
- }
- [sender setState:1];
-
- // Append sender's unabbrev stringValue onto ours (with TAB separation).
- if([stringValue count] <= 0) oldlen = 0;
- else oldlen = strlen((char *)[stringValue elementAt:0]);
- [stringValue setNumSlots:(oldlen + 1 + strlen(nextString) + 1)];
- sprintf((char *)[stringValue elementAt:0] + oldlen,
- (oldlen>0 ? "\t%s" : "%s"), nextString);
- return YES; // continue looping thru cells
- }
-
- // For internal use only.
- - recomputeStringValueFromSelection
- {
- [stringValue setNumSlots:0];
- [[self docView] sendAction:@selector(appendSelStringFrom:) to:self forAllCells:NO];
- return self;
- }
-
- - sendAction
- {
- // Sent by newly selected cells in matrix.
- // So recompute stringValue and make self firstResponder.
- [self recomputeStringValueFromSelection];
- [window makeFirstResponder:self];
- if(!action) return self;
- return [target perform:action with:self];
- }
-
- - sendDoubleAction
- {
- char *fileName, *nxt;
- int ok;
-
- // Sent by newly selected cell in matrix.
- // So recompute stringValue and make self firstResponder.
- [self recomputeStringValueFromSelection];
- [window makeFirstResponder:self];
-
- // Double-click means open files (if delegate exists and opens files).
- // Open files one by one (there may be many if msg sent by outside obj).
- if([stringValue count]>0 && [delegate respondsTo:@selector(openFile:ok:)])
- {
- fileName = (char *)[stringValue elementAt:0];
- nxt = strchr(fileName, separator);
- while(fileName)
- {
- if(nxt) *nxt = 0;
- [delegate openFile:fileName ok:&ok];
- if(nxt)
- {
- *nxt = separator;
- fileName = nxt+1;
- nxt = strchr(fileName, separator);
- }
- else fileName = nxt = 0;
- }
- }
-
- // Send doubleAction to target.
- if(!doubleAction) return self;
- return [target perform:doubleAction with:self];
- }
-
- - setTarget:anObject
- {
- target = anObject;
- [[self docView] setTarget:self];
- return self;
- }
-
- - setAction:(SEL)aSelector
- {
- action = aSelector;
- [[self docView] setAction:@selector(sendAction)];
- return self;
- }
-
- - setDoubleAction:(SEL)aSelector
- {
- doubleAction = aSelector;
- [[self docView] setDoubleAction:@selector(sendDoubleAction)];
- return self;
- }
-
- - target
- {
- return target;
- }
-
- - (SEL)action
- {
- return action;
- }
-
- - (SEL)doubleAction
- {
- return doubleAction;
- }
-
-
- // Editing.
-
- - setEditable:(BOOL)yn
- {
- isEditable = yn;
- return self;
- }
-
- - (BOOL)isEditable
- {
- return isEditable;
- }
-
- - (BOOL)acceptsFirstResponder
- {
- return YES;
- }
-
- - becomeFirstResponder
- {
- [self setBackgroundGray:NX_WHITE];
- [self update];
- return self;
- }
-
- - resignFirstResponder
- {
- [self setBackgroundGray:NX_LTGRAY];
- [self update];
- return self;
- }
-
- - keyDown:(NXEvent *)theEvent
- {
- if(theEvent->type!=NX_KEYDOWN) return self;
- if(!isEditable) return nil;
- switch(theEvent->data.key.charCode)
- {
- case NX_DELETE:
- [self delete:self];
- break;
- default:
- return nil;
- }
- return self;
- }
-
- - mouseDown:(NXEvent *)theEvent
- {
- // In case matrix is empty or does not fill view, capture mouse clicks.
- [super mouseDown:theEvent];
- if([window firstResponder] != self) [window makeFirstResponder:self];
- return self;
- }
-
- - delete:sender
- {
- char *fileName, *nxt;
- int ok;
-
- if(!isEditable) return self;
-
- // Let delegate delete selected "files" if it can.
- if([stringValue count]>0
- && [delegate respondsTo:@selector(removeFile:ok:)])
- {
- fileName = (char *)[stringValue elementAt:0];
- nxt = strchr(fileName, separator);
- while(fileName)
- {
- if(nxt) *nxt = 0;
- [delegate removeFile:fileName ok:&ok];
- if(nxt)
- {
- *nxt = separator;
- fileName = nxt+1;
- nxt = strchr(fileName, separator);
- }
- else fileName = nxt = 0;
- }
- }
-
- // Now remove selected names from list.
- [self removeSelection];
- [self update];
-
- // Notify delegate of user-induced change in list.
- if([delegate respondsTo:@selector(textDidChange:)])
- [delegate textDidChange:self];
- return self;
- }
-
- - cut:sender
- {
- const char *sval;
-
- if(!isEditable) return self;
-
- // Copy out string value...
- if(!(sval = [self stringValue])) return self;
- [[Pasteboard new] declareTypes:&NXAsciiPboard num:1 owner:self];
- [[Pasteboard new] writeType:NXAsciiPboard data:sval length:strlen(sval)];
-
- // Delete selection (and associated "files" if any).
- return [self delete:sender];
- }
-
- - copy:sender
- {
- char *fileName, *nxt;
- int ok;
- const char *sval;
-
- if(!(sval = [self stringValue])) return self;
-
- // Let delegate "prepare" selected "files" if it can.
- if([delegate respondsTo:@selector(prepFile:ok:)])
- {
- fileName = sval;
- nxt = strchr(fileName, separator);
- while(fileName)
- {
- if(nxt) *nxt = 0;
- [delegate prepFile:fileName ok:&ok];
- if(nxt)
- {
- *nxt = separator;
- fileName = nxt+1;
- nxt = strchr(fileName, separator);
- }
- else fileName = nxt = 0;
- }
- }
-
- // Copy out string value.
- [[Pasteboard new] declareTypes:&NXAsciiPboard num:1 owner:self];
- [[Pasteboard new] writeType:NXAsciiPboard data:sval length:strlen(sval)];
- [self update];
- return self;
- }
-
- - paste:sender
- {
- char *sval;
- int length;
-
- if(!isEditable) return self;
- [[Pasteboard new] readType:NXAsciiPboard data:&sval length:&length];
- [self setStringValue:sval]; //!!! is the data null-terminated?
- vm_deallocate(task_self(), (vm_address_t)sval, sizeof(char)*length);
- [self update];
-
- // Notify delegate of user-induced change in list.
- if([delegate respondsTo:@selector(textDidChange:)])
- [delegate textDidChange:self];
- return self;
- }
-
- - selectAll:sender
- {
- int row, nrows, ncols;
- id matrix;
- BOOL autodisplay;
-
- //!!! Hideous in action (autoDisplay isn't getting shut off?).
- matrix = [self docView];
- autodisplay = [matrix isAutodisplay];
- [matrix setAutodisplay:NO];
- [matrix getNumRows:&nrows numCols:&ncols];
- for(row=0; row<nrows; row++) [self selectEntryAt:row append:YES];
- [matrix setAutodisplay:autodisplay];
- [self update];
- return self;
- }
-
- - (int)openFile:(const char *)fileName ok:(int *)flag
- {
- // Default does nothing.
- return 0;
- }
-
- - (int)prepFile:(const char *)fileName ok:(int *)flag
- {
- // Default does nothing.
- return 0;
- }
-
- - (int)removeFile:(const char *)fileName ok:(int *)flag
- {
- // Default does nothing.
- return 0;
- }
-
- - textDidChange:sender
- {
- return self;
- }
-
-
- // String display control.
-
- - setEntryEnabled:(BOOL)yn at:(int)row
- {
- id matrix, cell;
-
- // Disabling a selected entry clears the selection.
- if(!yn && [self isEntrySelectedAt:row]) [self clearSelection];
- matrix = [self docView]; cell = [matrix cellAt:row :0];
- [cell setEnabled:yn];
- //!!! Note: textGray seems to be relative to the background??
- if(yn) [matrix drawCell:[cell setTextGray:NX_BLACK]];
- else [matrix drawCell:[cell setTextGray:NX_LTGRAY]];
- return self;
- }
-
- - (BOOL)isEntryEnabledAt:(int)row
- {
- return [[[self docView] cellAt:row :0] isEnabled];
- }
-
- - setDisabledOnEntry:(BOOL)yn
- {
- isDisabledOnEntry = yn;
- return self;
- }
-
- - (BOOL)isDisabledOnEntry
- {
- return isDisabledOnEntry;
- }
-
- - setAlphabetized:(BOOL)yn
- {
- //!!! Does not retroactively sort yet! Sorry!
- isAlphabetized = yn;
- return self;
- }
-
- - (BOOL)isAlphabetized
- {
- return isAlphabetized;
- }
-
- - (BOOL)isFirst:(const char *)firstString second:(const char *)secondString
- {
- // Standard NeXTstep string comparison.
- if(!secondString || !firstString) return NO;
- if(NXOrderStrings(secondString, firstString, NO, -1, NULL) > 0)
- return YES;
- else return NO;
- }
-
- - setAbbreviated:(BOOL)yn
- {
- int len, row, nrows, ncols;
- char *fullName, *abbrevName;
- id matrix, stringStorage;
-
- isAbbreviated = yn;
- matrix = [self docView];
- [matrix getNumRows:&nrows numCols:&ncols];
- for(row=0; row<nrows; row++)
- {
- stringStorage = [stringList objectAt:row];
- if(!(fullName = (char *)[stringStorage elementAt:0])) continue;
- len = strlen(fullName);
- [stringStorage setNumSlots:2*(len+1)];
- abbrevName = (char *)[stringStorage elementAt:(len+1)];
- fullName = (char *)[stringStorage elementAt:0];
- if(!abbrevName || !fullName) continue;
- *abbrevName = 0;
- [self abbreviate:fullName to:abbrevName];
- [[matrix cellAt:row :0] setStringValue:abbrevName];
- }
- [self update];
- return self;
- }
-
- - (BOOL)isAbbreviated
- {
- return isAbbreviated;
- }
-
- - abbreviate:(const char *)srcString to:(char *)destString
- {
- const char *abbr;
-
- // Show part after last '/'.
- if(!destString) return nil;
- if(!srcString) { *destString = 0; return self; }
- abbr = strrchr(srcString, '/');
- if(!abbr) abbr = srcString;
- else abbr++;
- strcpy(destString, abbr);
- return self;
- }
-
- @end
-
-
-
-